package com.ly.mp.busicen.rule.flow;

import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import com.ly.mp.busicen.rule.field.msg.IFieldMsgContainer;
import com.ly.mp.busicen.rule.flow.IFlowResultCtn.Risultato;
import com.ly.mp.busicen.rule.flow.action.ActionResult;
import com.ly.mp.busicen.rule.flow.action.IAction;
import com.ly.mp.busicen.rule.flow.action.IActionExecute;
import com.ly.mp.busicen.rule.flow.action.IActionExecuteContainer;
import com.ly.mp.busicen.rule.flow.action.IActionResult;
import com.ly.mp.busicen.rule.flow.action.IActionResult.Signal;
import com.ly.mp.busicen.rule.flow.filter.FlowFilterExecute;
import com.ly.mp.busicen.rule.instrumentation.IFlowInstrumentation;

public class FlowExecute implements IFlowExecute {
	
	@Autowired
	IActionExecuteContainer actionExecuteContainer;
	
	@Autowired
	IFieldMsgContainer fieldMsgContainer;
	
	@Autowired
	FlowFilterExecute flowFilterExecute;
	
	@Autowired
	IFlowInstrumentation instrumentation;
	
	static final Logger log = LoggerFactory.getLogger(FlowExecute.class);
	
	static final String START_ACTION="BEGIN";

	/**
	 * 
	 * @Description: 正真开始执行了
	 */
	@Override
	public IFlowResultCtn process(IFlowContext context) {
	    // 先找 ACTION_CODE 是 BEGIN 的开始执行
		Optional<IAction> optional = context.flowVolume().actions().stream().filter(m->START_ACTION.equals(m.action())).findFirst();
		FlowResultCtn result = FlowResultCtn.create();
		result.flowContext(context);
		if (!optional.isPresent()) {
			String message = String.format("流程【%s】对应【%s】不存在,当前用户【%s】集团编码【%s】品牌编码为【%s】",
					context.flowVolume().flow(),START_ACTION,FlowUserMode.currentUser().getUserName(),
					FlowUserMode.currentUser().getOemCode(),FlowUserMode.currentUser().getBrandCode());
			log.error(message);
			Throwable e = new FlowException(message);
			result.risultato(Risultato.EXCPT);
			result.excpt(e);
		}else {
			IAction startAction = optional.get();
			try {
				if(invoke(startAction, context, result)) {
					result.risultato(Risultato.FINISH);
				}
				if (result.risultato().equals(Risultato.EXCPT)) {
					log.error("流程【{}】规则引擎执行异常",context.flowVolume().flow(),result.excpt());
				}
				
			} catch (Exception e) {
				log.error("流程【{}】规则引擎执行异常",context.flowVolume().flow(),e);
				result.risultato(Risultato.EXCPT);
				result.excpt(e);
			}
		}
		return result;
	}
	boolean invoke(IAction action,IFlowContext context,IFlowResultCtn result) {
		instrumentation.beginActionInvoke(action, context, result);
		FlowResultCtn flowResult = (FlowResultCtn) result;
		// flowVolume.actions() 都是数据库中的脚本
		IFlowVolume flowVolume = context.flowVolume();
		
		IActionResult actionResult = ActionResult.create();
		
		if (!action.loopEnble()&&result.flowResults().stream().filter(m->m.action().equals(action.action())).findFirst().isPresent()) {
			String error = String.format("流程【%s】节点【%s】重复执行", flowVolume.flow(),action.action());
			throw new FlowException(error);
		}
		
		log.info("流程【{}】节点【{}】开始执行。。。",flowVolume.flow(),action.action());
		
		FlowResult resultDet = FlowResult.create();
		try {
			IActionExecute actionExecute = actionExecuteContainer.actionExecute(action.operation());
			actionResult = flowFilterExecute.invoke(actionExecute, action, context);
			
			BeanUtils.copyProperties(actionResult, resultDet);
			resultDet.setActionName(action.actionName());
			if (!StringUtils.isEmpty(actionResult.msg())) {
				String message = actionResult.msg();
				if (actionResult.convertMsg()) {
					message = fieldMsgContainer.getMsg(context.flowVolume().flow(), actionResult.msg()).getMsg();
				}
				resultDet.setMessage(message);
			}
			
			flowResult.addResult(resultDet);	
			
			if (Signal.BREAK.equals(actionResult.signal())) {
				flowResult.risultato(Risultato.BREAK);
				log.info("流程【{}】节点【{}】中断。。。",flowVolume.flow(),action.action());
				instrumentation.endActionInvoke(action, context, flowResult, resultDet);
				return false;
			}
			
			if (Signal.EXCPT.equals(actionResult.signal())) {
				flowResult.excpt(actionResult.excpt());
				flowResult.risultato(Risultato.EXCPT);
				log.info("流程【{}】节点【{}】异常。。。",flowVolume.flow(),action.action());
				instrumentation.endActionInvoke(action, context, flowResult, resultDet);
				return false;
			}
			String nextActionName = actionResult.nextAction();
			if ("EXIT".equals(nextActionName)) {
				log.info("流程【{}】节点【{}】执行结束。。。",flowVolume.flow(),action.action());
				instrumentation.endActionInvoke(action, context, flowResult, resultDet);
				return true;
			}
			Optional<IAction> optional = flowVolume.actions().stream().filter(m->nextActionName.equals(m.action())).findFirst();
			if (optional.isPresent()) {
				IAction nextAction = optional.get();
				instrumentation.endActionInvoke(action, context, flowResult, resultDet);
				return invoke(nextAction, context, flowResult);
			}else {
				String message = String.format("流程【%s】对应【%s】不存在,当前用户【%s】集团编码【%s】品牌编码为【%s】",
						context.flowVolume().flow(),nextActionName,FlowUserMode.currentUser().getUserName(),
						FlowUserMode.currentUser().getOemCode(),FlowUserMode.currentUser().getBrandCode());
				throw new FlowException(message);
			}			
			
		} catch (Exception e) {
			flowResult.excpt(e);
			flowResult.risultato(Risultato.EXCPT);
			String error = String.format("流程【%s】节点【%s】执行异常", flowVolume.flow(),action.action());
			log.error(error,e);
			instrumentation.endActionInvoke(action, context, flowResult, resultDet);
			return false;
		}
		finally {
			
		}
		
	}

}
